package com.zx._02_thread.线程池;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.junit.Test;

/**
 * @version v1.0
 * @Project: 20180808_thread
 * @Title: Lession_1_ExecutorService
 * @Description: 线程池
 * @author: zhangxue
 * @date: 2018年8月12日下午8:20:48
 * @company: yooli
 * @Copyright: Copyright (c) 2015
 */
public class Lession_1_Executors {

    /***********************JDK 1.5 ThreadPool**************************************/
    @Test
    public void test1() {
        //创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
        //线程池为无限大，当执行第二个任务时第一个任务已经完成，会复用执行第一个任务的线程，而不用每次新建线程。
        ExecutorService pool = Executors.newCachedThreadPool();
        this.thread(pool);
    }

    @Test
    public void test2() {
        //创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待
        ExecutorService pool = Executors.newFixedThreadPool(10);
        this.thread(pool);
    }

    @Test
    public void test3() {
        //创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
        ExecutorService pool = Executors.newSingleThreadExecutor();
        this.thread(pool);
    }

    @Test
    public void test4() {
        //创建一个定长线程池，支持定时及周期性任务执行。(1.普通线程池)
        ExecutorService pool = Executors.newScheduledThreadPool(10);
        this.thread(pool);
    }

    @Test
    public void test5() {
        //创建一个定长线程池，支持定时及周期性任务执行。(2. 定时任务)
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
        // 马上运行，任务消耗3秒。运行结束后等待2秒。【有空余线程时】，再次运行该任务
        pool.scheduleWithFixedDelay(() -> System.out.println(Thread.currentThread().getName() + "定时任务A"), 0, 2,
                TimeUnit.SECONDS);
        // 马上运行，任务消耗5秒，运行结束后等待2秒。【有空余线程时】，再次运行该任务
        pool.scheduleWithFixedDelay(() -> System.out.println(Thread.currentThread().getName() + "定时任务B"), 0, 2,
                TimeUnit.SECONDS);
        try {
            System.in.read();//输入内容后退出线程
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test6() {
        //创建一个定长线程池，支持定时及周期性任务执行。(1.普通线程池)
        ExecutorService pool = Executors.newSingleThreadScheduledExecutor();
        this.thread(pool);
    }

    @Test
    public void test7() {
        //创建一个定长线程池，支持定时及周期性任务执行。(2. 定时任务)
        ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
        // 马上运行，任务消耗3秒。运行结束后等待2秒。【有空余线程时】，再次运行该任务
        pool.scheduleWithFixedDelay(() -> System.out.println(Thread.currentThread().getName() + "定时任务A"), 0, 2,
                TimeUnit.SECONDS);
        // 马上运行，任务消耗5秒，运行结束后等待2秒。【有空余线程时】，再次运行该任务
        pool.scheduleWithFixedDelay(() -> System.out.println(Thread.currentThread().getName() + "定时任务B"), 0, 2,
                TimeUnit.SECONDS);
        try {
            System.in.read();//输入内容后退出线程
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /***********************JDK 1.8 ThreadPool**************************************/
    @Test
    public void test8() {
        //创建一个 work-stealing 线程池，使用目前机器上可用的处理器作为它的并行级别，并可以使用多个队列来减少竞争。
        // 我的电脑有4个CPU，所以创建了4个线程，当然也可以使用newWorkStealingPool(parallelism)创建指定线程数量的线程池
        ExecutorService pool = Executors.newWorkStealingPool();
        this.thread(pool);
    }

    /***********************common method**************************************/
    /**
     * @param pool
     * @Title: 提供公共的线程池调用方法
     * @date: 2018年8月12日下午8:42:00
     */
    public void thread(ExecutorService pool) {
        //创建一个线程
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100L);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //向线程池中提交两个线程去执行。
        for (int i = 0; i < 100; i++) {
            pool.submit(t);
        }
        pool.shutdown();
        try {
            System.in.read();//输入内容后退出线程
        } catch (IOException e) {
            e.printStackTrace();
        }
        pool.shutdownNow();
    }

}
